#include "actions.hpp"
extern TableSymb ts;
extern TableIdent ti;

void exitErrorDebug(int exitCode)
{
	cerr << endl << "Debug exit: " << endl << endl
		<< "Table identifiants : " << endl;
	ti.print();
	cerr << endl << "Table symboles : " << endl;
	ts.print();
	cerr << "------------" << endl;
	exit(exitCode);
}

Ptr * castOrExitPtr(Symbole * symb)
{
	Ptr *symbPtr = dynamic_cast<Ptr *>(symb);
	if(symbPtr == NULL) {
		cerr << "dynamic_cast<Ptr *> : fail." << endl;
		exitErrorDebug(30);
	}
	return symbPtr;
}

Var * castOrExitVar(Symbole * symb)
{
	Var *symbVar = dynamic_cast<Var *>(symb);
	if(symbVar == NULL) {
		cerr << "dynamic_cast<Var *> : fail." << endl;
		exitErrorDebug(30);
	}
	return symbVar;
}

Cste * castOrExitCste(Symbole * symb)
{
	Cste *symbCste = dynamic_cast<Cste *>(symb);
	if(symbCste == NULL) {
		cerr << "dynamic_cast<Cste *> : fail." << endl;
		exitErrorDebug(30);
	}
	return symbCste;
}

SymboleAff * castOrExitSymbAff(Symbole * symb)
{
	SymboleAff *symbAff = dynamic_cast<SymboleAff *>(symb);
	if(symbAff == NULL) {
		cerr << "dynamic_cast<SymboleAff *> : fail." << endl;
		exitErrorDebug(30);
	}
	return symbAff;
}

SymboleVal * castOrExitSymbVal(Symbole * symb)
{
	SymboleVal *symbVal = dynamic_cast<SymboleVal *>(symb);
	if(symbVal == NULL) {
		cerr << "dynamic_cast<SymboleVal *> : fail." << endl;
		exitErrorDebug(30);
	}
	return symbVal;
}


/* --------------------------------	*/
/* Declarations 					*/
/* --------------------------------	*/

void actionProgHeader( tAttrIdent& progName )
{
	Program *symbProg = new Program();
	ts.add(progName.id, symbProg);
}

void actionDeclConst( tAttrIdent& ident, tAttrExpr& expr )
{
	Cste *cste = new Cste(expr.val);
	ts.add(ident.id, cste);
}

void actionDeclVar ( tAttrListIdent& listIdent, tAttrBaseType& baseType )
{
	unsigned int i;
	SymboleAff * symbAff;
	for(i = listIdent.idBas; i <= listIdent.idHaut; i++) {
		//cout << *ti.getIdent(i) << endl;
		symbAff = castOrExitSymbAff(ts.get(i));
		symbAff->setType(baseType.type);
	}
	//cout << "Decl Var : " << endl
	//	<< "type : " << baseType.type->getName() << endl;
}

void actionListIdent ( tAttrListIdent& listIdent, tAttrIdent& ident )
{
	Var *symbVar = new Var();
	ts.add(ident.id, symbVar);
	listIdent.idHaut = ident.id;
	cout << "idHaut :" << listIdent.idHaut << endl;
	//listIdent.idents->push_back(ident.id);
}

void actionBaseTypeInt ( tAttrBaseType& baseType )
{
	baseType.type = (Type *)TypeGenerator::getInstance().getIntType();
}

void actionBaseTypeReal ( tAttrBaseType& baseType )
{
	baseType.type = (Type *)TypeGenerator::getInstance().getRealType();
}

void actionListIdentDernier ( tAttrListIdent& listIdent, tAttrIdent& ident )
{
	Var *symbVar = new Var();
	ts.add(ident.id, symbVar);
	listIdent.idBas = ident.id;
	cout << "idBas : " << listIdent.idBas << endl;
}

/* --------------------------------	*/
/* --------------------------------	*/

void actionListInstr ( tAttrListInstr& retour,
		const tAttrInstr& instr, const tAttrListInstr& liste ) {
}

void actionListInstr ( tAttrListInstr& retour )
{
	printf("Empty/End of input\n");
	cout << endl << "Table des symboles :" << endl;
	ts.print();
	cout << endl;
}

void handleVarAffect(Var *var, const tAttrExpr& expr) {
}
void handlePtrAffect(Ptr *ptr, const tAttrExpr& expr) {
}

void actionInstr ( tAttrInstr& instr, tAttrVarExpr& varExpr,
		const tAttrExpr& expr )
{
	if(castOrExitCste(varExpr.symb))
	{
		// C'est une constante, pas de cste := valeur.
		cerr << "Erreur: affectation dans une constante." << endl;
		//exitErrorDebug(33);
	} else {
		exitErrorDebug(33);
		//varExpr.symb->setValue(expr.value);
	}
}

/*
void actionInstr ( tAttrInstr& instr, tAttrVarExpr& var,
		const tAttrExpr& expr )
{
	// DEBUG
	// printf("&ident %u: %p\n", ident.id, &ident);

	Var *symbVar = new Var();

	if(expr.calculable) {

		ident.val = expr.val;

		symbVar->setValue(expr.val);
		ts.add(ident.id, symbVar);
		//ident.calculable = true;

		//printf("Expression : %f\n", expr.val);
		//printf("ident %u (%s)= %f\n", ident.id, ts.get(ident.id), expr.val);
		cout << "ident " << ident.id << " ("
			<< *ti.getIdent(ident.id) << ") = " << expr.val << endl;

	} else {

		ts.add(ident.id, symbVar);
		//ident.calculable = false;

		printf("ident %u : pas calculable\n",
				ident.id);

	}

}
*/

void actionAdd ( tAttrExpr& retour, const tAttrExpr& opg,
		const tAttrExpr& opd )
{
	if(opg.calculable && opd.calculable) {
		retour.val = opg.val + opd.val;
		retour.calculable = true;
		printf("%f + %f = %f\n",
				opg.val, opd.val, retour.val);
	} else {
		printf("+ : Pas calculable\n");
	}

}

void actionSub ( tAttrExpr& retour, const tAttrExpr& opg,
		const tAttrExpr& opd )
{
	if(opg.calculable && opd.calculable) {
		retour.val = opg.val - opd.val;
		retour.calculable = true;
		printf("%f - %f = %f\n",
				opg.val, opd.val, retour.val);
	} else {
		printf("+ : Pas calculable\n");
	}

}

void actionMul ( tAttrExpr& retour, const tAttrExpr& opg,
		const tAttrExpr& opd )
{
	if(opg.calculable && opd.calculable) {
		retour.val = opg.val * opd.val;
		retour.calculable = true;
		printf("%f * %f = %f\n",
				opg.val, opd.val, retour.val);
	} else {
		printf("+ : Pas calculable\n");
	}

}

void actionDiv ( tAttrExpr& retour, const tAttrExpr& opg,
		const tAttrExpr& opd )
{

	if(opg.calculable && opd.calculable) {
		retour.val = opg.val / opd.val;
		retour.calculable = true;
		printf("%f / %f = %f\n",
				opg.val, opd.val, retour.val);
	} else {
		printf("+ : Pas calculable\n");
	}

}

void actionExp ( tAttrExpr& retour, const tAttrExpr& opg,
		const tAttrExpr& opd )
{
	if(opg.calculable && opd.calculable) {
		retour.val = pow(opg.val, opd.val);
		retour.calculable = true;
		printf("%f ** %f = %f\n",
				opg.val, opd.val, retour.val);
	} else {
		printf("+ : Pas calculable\n");
	}

}

void actionSub ( tAttrExpr& retour, const tAttrExpr& operand )
{
	if(operand.calculable) {
		retour.val = -operand.val;
		retour.calculable = true;
		printf("-%f = %f\n", operand.val, retour.val);
	} else {
		printf("- unaire : Pas calculable\n");
	}
}

void actionAdd ( tAttrExpr& retour, const tAttrExpr& operand )
{
	if(operand.calculable) {
		retour.val = fabs(operand.val);
		retour.calculable = true;
		printf("+%f = %f\n", operand.val, retour.val);
	} else {
		printf("+ unaire : Pas calculable\n");
	}
}

void actionBrackets ( tAttrExpr& retour, const tAttrExpr& expr )
{
	if(expr.calculable) {
		retour.val = expr.val;
		retour.calculable = true;
		printf("%f = (%f)\n", expr.val, retour.val);
	} else {
		printf("( expr ) : Pas calculable\n");
	}
}

void actionConstante ( tAttrExpr& retour, const tAttrEntier& entier ){
	retour.val = entier.val;
	retour.calculable = true;
	//printf("ENTIER : %d\n", entier.val);
}

void actionConstante ( tAttrExpr& retour, const tAttrReel& reel ){
	retour.val = reel.val;
	retour.calculable = true;
	//printf("REEL : %f\n", reel.val);

}

void actionIdent ( tAttrVarExpr& retour, const tAttrIdent& ident ){

	// DEBUG
	// printf("&ident %u: %p\n", ident.id, &ident);

	//if(ident.calculable) {
	if(ts.get(ident.id) == NULL) {
		cerr << "ident " << ident.id << " (" <<
			*ti.getIdent(ident.id) << ") : inconnu. Impossible "
			<< "de lui affecter une valeur ou de l'utiliser pour des "
			<< "calculs." << endl;
		exitErrorDebug(29);

	}
	//exitErrorDebug(30);
	cout << "zoeriheiorhehr" << endl;
	cout << ident.id << endl;
	SymboleVal *symbVal = castOrExitSymbVal(ts.get(ident.id));
	cout << "zoeriheiorhehr" << endl;

	if(symbVal->isAffected()) {
		cout << "pokogpf,gfopgj," << endl;
		retour.val = symbVal->getValue();
		retour.calculable = true;
		//printf("ident %u : %f\n", ident.id, symbVal->getValue());
		cout << "ident " << ident.id << " (" <<
			*ti.getIdent(ident.id) << ") : " << *symbVal << endl;

	} else {
		//printf("ident %u : Pas de valeur\n", ident.id);
		cout << "ident " << ident.id << " (" <<
			*ti.getIdent(ident.id) << ") : pas de valeur." << endl;
	}
	//exitErrorDebug(44);

}

void actionPtr ( tAttrVarExpr& retour, const tAttrIdent& ident )
{
	Symbole *symb = ts.get(ident.id);
	if(symb == NULL) {
		cout << "ActionPtr : ptr " <<
			*ti.getIdent(ident.id) << " inconnu." << endl;
	} else {
		Ptr *symbPtr = castOrExitPtr(symb);
		// L'ident est dans la table des symbole, mais ce n'est pas un
		// pointeur.

		SymboleAff *symbAff =
			dynamic_cast<SymboleAff *>((Symbole *)symbPtr->getPointed());
		if(symbAff != NULL) {
			// C'est un pointeur sur cste/var.

			/*
			if(symbAff->isAffected() == false) {
				cout << "ActionPtr : dereferencement du ptr " <<
					*ti.getIdent(ident.id) << " sur une variable "
					"declare mais non assigne." << endl;
			} else {
				retour.var = symbAff->getValue();
			}
			*/
			retour.symb = symbAff;
			retour.calculable = false;

		} /*else if(dynamic_cast<SymboleCallable *>
			(symbPtr->getPointed()) != NULL)*/
		else {
			// Pointeur sur type inconnu ? (impossible normalement).
			if(symbAff == NULL) {
				cerr << "dynamic_cast<SymboleAff *> : fail." << endl;
				exitErrorDebug(30);
			}
		}
	}


	/*
	if(ts.get(ident.id) == NULL) {
		cout << "declaration ptr sur ident " << *ti.getIdent(ident.id) <<
			" inconnu." << endl;
	}
	cout << "declaration ptr sur " << ident.id << " (" <<
		*ti.getIdent(ident.id) << ") : pas de valeur." << endl;
	*/
}
